<template>
  <div>
    <el-container>
      <el-header>
        <span>Python代码执行器</span>
        <el-button type="primary" @click="showExampleDialog = true" style="margin-left: 20px;">
          选择示例代码
        </el-button>
      </el-header>

      <el-main>
        <div class="executor-container">
          <!-- 知识点讲解区 -->
          <div class="knowledge-panel" v-if="currentExample">
            <h3>{{ currentExample.name }}</h3>
            <div class="knowledge-content">
              <h4>知识点讲解：</h4>
              <p>{{ currentExample.knowledge }}</p>
            </div>
          </div>

          <!-- 示例代码展示区 -->
          <div class="example-display" v-if="currentExample">
            <div class="code-header">
              <span>示例代码</span>
              <el-button 
                type="text" 
                @click="copyExampleCode"
                icon="el-icon-document-copy"
              >
                复制代码
              </el-button>
            </div>
            <pre class="example-code">{{ currentExample.code }}</pre>
          </div>

          <!-- 用户代码执行区 -->
          <div class="execution-area">
            <div class="cell-toolbar">
              <el-button 
                @click="executeCode" 
                type="primary"
                :loading="loading"
              >
                <i class="el-icon-video-play"></i> 执行代码
              </el-button>
              <el-button 
                @click="resetCode"
                type="text"
              >
                重置代码
              </el-button>
            </div>
            <el-input
              v-model="code"
              type="textarea"
              :rows="10"
              resize="none"
              placeholder="在此输入或修改代码..."
            ></el-input>
          </div>

          <!-- 输出区 -->
          <div class="output-container" v-if="output || error">
            <div class="output-title">执行结果:</div>
            <pre :class="{'error-output': error}">{{ output || error }}</pre>
          </div>
        </div>
      </el-main>

      <!-- 示例代码选择对话框 -->
      <el-dialog 
        title="选择示例代码" 
        :visible.sync="showExampleDialog" 
        width="60%"
        :close-on-click-modal="false"
      >
        <el-table :data="examples" style="width: 100%" height="400">
          <el-table-column prop="name" label="示例名称" width="180"></el-table-column>
          <el-table-column prop="description" label="描述"></el-table-column>
          <el-table-column label="操作" width="120">
            <template slot-scope="scope">
              <el-button 
                @click="loadExample(scope.row)" 
                type="text"
                size="small"
              >
                选择
              </el-button>
            </template>
          </el-table-column>
        </el-table>
      </el-dialog>
    </el-container>
  </div>
</template>

<script>
export default {
  name: 'PythonExecutor',
  data() {
    return {
      code: '',
      output: '',
      error: '',
      loading: false,
      showExampleDialog: false,
      currentExample: null,
      examples: [
        {
          name: "1. NumPy基础运算",
          description: "数组创建和数学运算",
          knowledge: "NumPy是Python科学计算的基础库，提供高性能的多维数组对象和各种数学运算函数。\n\n关键知识点：\n- 数组创建：np.array()\n- 向量化运算：避免Python循环，直接对数组进行数学运算\n- 广播机制：不同形状数组间的运算规则",
          code: `import numpy as np

# 创建数组
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])

# 基本运算
print("加法:", a + b)
print("乘法:", a * b)
print("点积:", np.dot(a, b))
print("平方根:", np.sqrt(a))
print("指数:", np.exp(a))`
        },
        {
          name: "2. 数组统计运算",
          description: "数组统计方法",
          knowledge: "NumPy提供多种统计计算方法。\n\n关键知识点：\n- 聚合计算：sum(), mean(), max()等\n- 轴方向计算\n- 累加计算\n- 布尔运算统计",
          code: `import numpy as np

arr = np.array([[1, 2, 3], [4, 5, 6]])

print("数组总和:", np.sum(arr))
print("每列平均值:", np.mean(arr, axis=0))
print("每行最大值:", np.max(arr, axis=1))
print("累积和:", np.cumsum(arr))
print("大于3的元素数量:", np.sum(arr > 3))`
        },
        {
          name: "3. 解线性方程组",
          description: "使用NumPy解方程组",
          knowledge: "NumPy可以方便地求解线性方程组。\n\n关键知识点：\n- 方程组表示：Ax = b\n- 解法：np.linalg.solve()\n- 特殊情况处理：奇异矩阵、欠定/超定系统",
          code: `import numpy as np

# 系数矩阵
A = np.array([[3, 1], [1, 2]])
# 常数项
b = np.array([9, 8])

# 解方程
x = np.linalg.solve(A, b)
print("解:", x)

# 验证
print("验证:", np.dot(A, x))`
        },
        {
          name: "4. 随机数生成",
          description: "概率分布抽样",
          knowledge: "NumPy的随机数生成功能。\n\n关键知识点：\n- 随机种子设置\n- 常见概率分布\n- 随机抽样\n- 排列组合",
          code: `import numpy as np

# 设置随机种子(保证可重复性)
np.random.seed(42)

# 生成随机数
print("均匀分布:", np.random.uniform(0, 1, 5))
print("正态分布:", np.random.normal(0, 1, 5))
print("整数随机:", np.random.randint(0, 10, 5))

# 数组洗牌
arr = np.array([1, 2, 3, 4, 5])
np.random.shuffle(arr)
print("洗牌后:", arr)`
        },
        {
          name: "5. 统计计算",
          description: "基础统计分析",
          knowledge: "NumPy提供各种统计计算函数。\n\n关键知识点：\n- 描述性统计：均值、中位数、标准差等\n- 相关性计算\n- 直方图统计\n- 随机数生成",
          code: `import numpy as np

# 生成随机数据
data = np.random.normal(5, 2, 1000)  # 均值为5，标准差为2的正态分布

# 基本统计量
print("均值:", np.mean(data))
print("中位数:", np.median(data))
print("标准差:", np.std(data))
print("最小值:", np.min(data))
print("最大值:", np.max(data))
print("25百分位数:", np.percentile(data, 25))`
        },
        {
          name: "6. 数值积分",
          description: "使用SciPy计算积分",
          knowledge: "SciPy提供高级数值积分功能。\n\n关键知识点：\n- 定积分计算\n- 无限区间积分\n- 多重积分\n- 特殊函数积分",
          code: `from scipy import integrate
import numpy as np

# 定义被积函数
def f(x):
    return np.exp(-x**2)

# 计算积分
result, error = integrate.quad(f, -np.inf, np.inf)
print("积分结果:", result)
print("理论值 √π:", np.sqrt(np.pi))
print("误差估计:", error)`
        },
        {
          name: "7. 方程求根",
          description: "非线性方程求解",
          knowledge: "SciPy可以求解非线性方程。\n\n关键知识点：\n- 单变量方程求根\n- 多变量方程组求解\n- 数值方法选择\n- 收敛性判断",
          code: `from scipy.optimize import root
import numpy as np

# 定义方程
def equation(x):
    return x**3 + 2*x**2 - 5*x - 6

# 求解
sol = root(equation, x0=1)  # 初始猜测x0=1
print("方程根:", sol.x)
print("函数值:", equation(sol.x))`
        },
        {
          name: "8. 插值计算",
          description: "数据插值方法",
          knowledge: "SciPy提供多种插值方法。\n\n关键知识点：\n- 线性插值\n- 多项式插值\n- 样条插值\n- 外推处理",
          code: `from scipy import interpolate
import numpy as np

# 原始数据
x = np.array([0, 1, 2, 3, 4, 5])
y = np.array([0, 0.8, 0.9, 0.1, -0.8, -1.0])

# 创建插值函数
f = interpolate.interp1d(x, y, kind='cubic')

# 使用插值
x_new = np.linspace(0, 5, 50)
y_new = f(x_new)

print("在x=2.5处的插值:", f(2.5))`
        },
        {
          name: "9. 数组排序",
          description: "数组搜索与排序",
          knowledge: "NumPy的排序和搜索功能。\n\n关键知识点：\n- 快速排序\n- 部分排序\n- 条件筛选\n- 唯一值查找",
          code: `import numpy as np

arr = np.array([3, 1, 4, 2, 5])

print("排序:", np.sort(arr))
print("前3小:", np.partition(arr, 3)[:3])
print("大于2的元素:", arr[arr > 2])
print("唯一值:", np.unique([1, 1, 2, 2, 3]))`
        }
      ]
    }
  },
  methods: {
    async executeCode() {
      if (!this.code.trim()) {
        this.$message.warning('请输入Python代码');
        return;
      }

      this.loading = true;
      this.error = '';
      this.output = '';

      try {
        const { data } = await this.$http({
          url: this.$http.adornUrl("/python/execute"),
          method: "post",
          data: this.$http.adornData({ code: this.code }, false),
        });

        if (data.success) {
          // 过滤掉Python版本信息
          const outputParts = data.output.split('---------------------------------');
          this.output = outputParts.length > 1 ? outputParts[1].trim() : data.output;
        } else {
          this.error = data.error || '执行失败';
        }
      } catch (error) {
        const errorMsg = (error.response && error.response.data && error.response.data.error) || error.message;
        this.error = `请求错误: ${errorMsg}`;
      } finally {
        this.loading = false;
      }
    },
    
    loadExample(example) {
      this.currentExample = example;
      this.code = example.code;
      this.output = '';
      this.error = '';
      this.showExampleDialog = false;
      this.$message.success(`已加载示例: ${example.name}`);
    },
    
    resetCode() {
      if (this.currentExample) {
        this.code = this.currentExample.code;
        this.output = '';
        this.error = '';
      } else {
        this.code = '';
      }
    },
    
    copyExampleCode() {
      if (this.currentExample) {
        navigator.clipboard.writeText(this.currentExample.code)
          .then(() => this.$message.success('代码已复制到剪贴板'))
          .catch(() => this.$message.error('复制失败'));
      }
    }
  }
}
</script>

<style scoped>
.executor-container {
  max-width: 900px;
  margin: 0 auto;
  border: 1px solid #ebeef5;
  border-radius: 4px;
  padding: 20px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}

.knowledge-panel {
  background-color: #f8f9fa;
  border-radius: 4px;
  padding: 15px;
  margin-bottom: 20px;
  border-left: 4px solid #409EFF;
}

.knowledge-content h4 {
  color: #409EFF;
  margin-top: 0;
}

.knowledge-content p {
  white-space: pre-wrap;
  line-height: 1.6;
}

.example-display {
  margin-bottom: 20px;
  border: 1px solid #ebeef5;
  border-radius: 4px;
}

.code-header {
  background-color: #f5f7fa;
  padding: 8px 15px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  border-bottom: 1px solid #ebeef5;
}

.example-code {
  margin: 0;
  padding: 15px;
  background-color: #fafafa;
  font-family: 'Courier New', monospace;
  font-size: 0.9em;
  line-height: 1.5;
  overflow-x: auto;
  max-height: 300px;
  display: block;
}

.execution-area {
  margin-bottom: 25px;
  border: 1px solid #ebeef5;
  border-radius: 4px;
  overflow: hidden;
}

.cell-toolbar {
  background-color: #f5f7fa;
  padding: 8px 15px;
  border-bottom: 1px solid #ebeef5;
}

.output-container {
  background-color: #f5f7fa;
  padding: 15px;
  border-radius: 4px;
  margin-top: 20px;
}

.output-title {
  font-size: 0.9em;
  color: #909399;
  margin-bottom: 5px;
}

pre {
  margin: 0;
  white-space: pre-wrap;
  font-family: 'Courier New', monospace;
  font-size: 0.9em;
  line-height: 1.5;
}

.error-output {
  color: #f56c6c;
}

.el-header {
  display: flex;
  align-items: center;
  border-bottom: 1px solid #dcdfe6;
  padding: 0 20px;
  height: 60px;
  background-color: #409EFF;
  color: white;
  font-size: 1.2em;
}

.el-dialog__body {
  padding: 10px 20px;
}
</style>